Home

Introduction to Resources

 

Resources Fundamentals

 

Introduction

A resource is an object that cannot be defined in C++ terms but that is needed to complete a program. In the strict sense, it is text that contains a series of terms or words that the program can interpret through code. Examples of resources are menus, icons, cursors, dialog boxes, sounds, etc.

There are various means of creating a resource and the approach you use depends on the resource. For example, some resources are completely text-based, such is the case for the String Table or the Accelerator Table. Some other resources must be designed, such is the case for icons and cursors. Some other resources can be imported from another, more elaborate application, such is the case for high graphic pictures. Yet some resources can be a combination of different resources.

Resource Creation

As mentioned already, resources are not a C++ concept but a Microsoft Windows theory of completing an application. Therefore, the programming environment you use may or may not provide you with the means of creating certain resources. Some environments like Borland C++ Builder or Visual C++ (6 and .NET) are complete with (almost) anything you need to create (almost) any type of resources. Some other environments may appear incomplete, allowing you to create only some resources, the other resources must be created using an external application not provided; such is the case for C++BuilderX.

Upon creating a resource, you must save it. Some resources are created as their own file, such is the case for pictures, icons, cursors, sound, etc. Each of these resources has a particular extension depending on the resource. After creating the resources, you must add them to a file that has the extension .rc. Some resources are listed in this file using a certain syntax. That's the case for icons, cursors, pictures, sounds, etc. Some other resources must be created directly in this file because these resources are text-based; that's the case for menus, strings, accelerators, version numbers, etc.

After creating the resource file, you must compile it. Again, some environments, such as Microsoft Visual C++, do this automatically when you execute the application. Some other environments may require you to explicitly compile the resource. That's the case for Borland C++ Builder and C++BuilderX. (The fact that these environments require that you compile the resource is not an anomaly. For example, if you create a Windows application that is form-based in C++ Builder 6 or Delphi, you can easily add the resources and they are automatically compiled and added to the application. If you decide to create a Win32 application, C++ Builder believes that you want to completely control your application; so, it lets you decide when and how to compile a resource. This means that it simply gives you more control).

 

Practical Learning Practical Learning: Introducing Windows Resources

  1. If you are using Borland C++ Builder, create a new Win32 application using Console Wizard as we did in Lesson 1
    1. Save the project as Resources1 in a new folder called Resources1
    2. Save the unit as Exercise.cpp
  2. If you are using Microsoft Visual C++, 
    1. Create a new Win32 Application as done the previous time. Save the project as Resources1 and 
    2. Create a new C++ Source file named Exercise.cpp
  3. Implement the source file as follows(for Borland C++ Builder, only add the parts that are not in the code):
     
    //---------------------------------------------------------------------------
    #include <windows.h>
    #pragma hdrstop
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    //---------------------------------------------------------------------------
    const char *ClsName = "FundApp";
    const char *WndName = "Resources Fundamentals";
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg,
    			      WPARAM wParam, LPARAM lParam);
    //---------------------------------------------------------------------------
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine, int nCmdShow)
    {
    	MSG        Msg;
    	HWND       hWnd;
    	WNDCLASSEX WndClsEx;
    
    	// Create the application window
    	WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    	WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    	WndClsEx.lpfnWndProc   = WndProcedure;
    	WndClsEx.cbClsExtra    = 0;
    	WndClsEx.cbWndExtra    = 0;
    	WndClsEx.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    	WndClsEx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    	WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	WndClsEx.lpszMenuName  = NULL;
    	WndClsEx.lpszClassName = ClsName;
    	WndClsEx.hInstance     = hInstance;
    	WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    
    	// Register the application
    	RegisterClassEx(&WndClsEx);
    
    	// Create the window object
    	hWnd = CreateWindowEx(0,
                              ClsName,
                              WndName,
                   			  WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT,
                   			  CW_USEDEFAULT,
                              CW_USEDEFAULT,
                   			  CW_USEDEFAULT,
                              NULL,
                              NULL,
                              hInstance,
                              NULL);
    	
    	// Find out if the window was created
    	if( !hWnd ) // If the window was not created,
    		return FALSE; // stop the application
    
    	// Display the window to the user
    	ShowWindow(hWnd, nCmdShow);// SW_SHOWNORMAL);
    	UpdateWindow(hWnd);
    
    	// Decode and treat the messages
    	// as long as the application is running
    	while( GetMessage(&Msg, NULL, 0, 0) )
    	{
                 TranslateMessage(&Msg);
                 DispatchMessage(&Msg);
    	}
    
    	return Msg.wParam;
    }
    //---------------------------------------------------------------------------
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg,
    			   WPARAM wParam, LPARAM lParam)
    {
        switch(Msg)
        {
        case WM_DESTROY:
            PostQuitMessage(WM_QUIT);
            break;
        default:
            // Process the left-over messages
            return DefWindowProc(hWnd, Msg, wParam, lParam);
        }
        // If something was not done, let it go
        return 0;
    }
    //---------------------------------------------------------------------------
  4. Execute the application to test it

 

Cursors

 

Introduction

A cursor is an object used to show or represent the current position of the mouse on the screen. Microsoft Windows ships with many cursors as follows:

IDC_APPSTARTING IDC_APPSTARTING IDC_ARROW IDC_ARROW IDC_CROSS IDC_HAND
IDC_HELP IDC_IBEAM IDC_ICON Not Used(*) IDC_NO
IDC_SIZE Not Used(*) IDC_SIZEALL IDC_SIZENESW IDC_SIZENS
IDC_SIZENWSE IDC_SIZEWE IDC_UPARROW IDC_WAIT

(*) The IDC_ICON and the IDC_SIZE cursors should not be used anymore.

To use a cursor, the user points the mouse on a specific item. Because a cursor can be large and because many areas of a window can act upon receiving the mouse, the cursor has a special area called a hot spot so that, no matter how big the cursor is, the mouse can apply its behavior only on what the hot spot touches. For an arrow cursor, which is the most widely used cursor, the hot spot is located on the tip of the arrow pointing to the top-left corner. When you create your own cursor, you can position the hot spot anywhere on the cursor as you wish but you must always know where the hot spot of your cursor is and you should always make it obvious to the user.

 

Cursor Creation

To use any of the above cursors, simply pass its name as the second argument to the LoadCursor() function. Here is an example:

LoadCursor(NULL, IDC_HELP);

Creating your own cursor or a few cursors for your application involves a few steps. These steps can be different depending on the programming environment you are using; but the process is the same.

You should first create a cursor. You can copy one of the existing cursors that ship with your programming environment. Both Borland C++ Builder and Microsoft Visual C++ install many cursors. You can still create your own cursor from scratch. For Borland C++ Builder, this can be done using the Image Editor, which is a separate application that ships with the compiler. For Microsoft Visual C++, you can do this using the built-in image editor. The cursor is its own file with the extension .cur.

After creating and possibly testing the cursor, you must create a header file, usually called Resource.h, in which you define the cursor. In this file, each cursor must be defined with the formula:

#define Identifier Constant

The #define preprocessor is required. The identifier must be a non-quoted string that will serve to identify the cursor. The Constant must an integer with a unique value in the file.

After creating the header file, you must create the main resource file. This file has an extension of .rc and it usually has the same name as the project but this is only a habit. In the resource file, you should first include the header file you just created. In the file, each resource must be represented. For a cursor, you use the formula:

Identifier CURSOR FileName

The Identifier must be the same you defined in the Resource header file. The keyword CURSOR must be used to let the compiler know that this particular resource is a cursor, making it distinct from other resources such as icons or bitmaps, etc. The FileName must be the cursor with extension .cur that you had created already.

To use the resource (.rc) file in your project, you must explicitly Add it to your project. Neither Borland C++ Builder nor Microsoft Visual C++ will add this rc file for you. The main difference is that, with Borland C++ Builder, you can add this rc file before or after compiling it, as long as the compile is aware of it before building the whole project. With Microsoft Visual C++, you should first (although you don't have to) add the rc file to your project. In fact, this makes it easy for Microsoft Visual C++ to compile the rc file for you.

Using Borland C++ Builder

  1. To create the cursor file, on the main menu, click Tools -> Image Editor
  2. When the  Image Editor displays, on the main menu, click File -> New -> Cursor File (.cur). Press Ctrl + I three times to zoom in.
  3. Design the cursor as follows:
     
  4. To define the hot spot, on the main menu of Image Editor, click Cursor -> Set Hot Spot... Set the Horizontal (X) and the Vertical (Y) values to 15 each and click OK 
  5. To save the cursor, on the main menu of Image Editor, click File -> Save
  6. Locate the folder where the current exercise is located and display in the Save In combo box
  7. Replace the contents of the File Name edit box with Target
    The right extension (.cur) will be added to the file
  8. Click Save and return to C++ Builder
  9. To create the resource header file, on the main menu, click File -> New... or File -> New -> Other...
  10. In the New Items dialog box, click Header File and click OK
  11. In the header file, type:
     
    #define IDC_TARGET  1000
  12. To save the header file, on the Standard toolbar, click the Save All button
  13. Type Resource.h and make sure you add the extension
     
    Save File As
  14. Click Save
  15. To create the actual resource file, on the main menu, click File -> New... or File -> New -> Other...
  16. In the New Items dialog box, scroll down, click the Text icon, and click OK.
  17. In the empty file, type:
     
    #include "Resource.h"
    
    IDC_TARGET  CURSOR  "Target.cur"
  18. To save the resource file, on the Standard toolbar, click the Save All button.
  19. Type "Resources1.rc"
    The reason for the double-quotes is to make sure that not only the file is not saved with a txt extension but also it is actually saved with the rc extension
     
    Save Resource File
  20. Click Save
  21. To add the resource file to the current project, on the main menu, click Project -> Add to Project...
  22. In the Files of Type combo box, select Resource File (*.rc)
     
    Add to Project
  23. In the list box, click Resources.rc.rc and click Open

Using Microsoft Visual C++

  1. To create the cursor, on the main menu, click Insert -> Resource... In the Insert Resource dialog box, click Cursor and click New
  2. If you are using MSVC 6, on the main menu, click View -> Properties...
    In the Properties window, change the ID to IDC_TARGET and press Tab
    Make sure the file name is changed to target.cur and press Enter
  3. Design the cursor as follows:
     
  4. To define the hot spot, on the toolbar of the editor, click the Set Hot Spot button. Click the middle of the square:
     
  5. To save and close the resource file, click its system Close button (the system Close button of the child window) of the cursor and close the child window of the script (the window with Script1 or Script2)
  6. When asked to save the script, click Yes
  7. Locate the folder where the current exercise is located and display in the Save In combo box. Change the name of the file to Resources1.rc
    The right extension (.rc) will be added to the file
     
  8. Click Save
  9. To add the resource file to the current project, on the main menu, click Project -> Add To Project -> Files...
  10. In the list box, click Win32B.rc and click OK
  11. In the Workspace, click the ResourceView tab.
    Expand the Win32B resource node by clicking its + button. Expand the Cursor node.
    Make sure the IDC_TARGET cursor is present

Custom Cursors

After creating the resource file, you must compile it. After the rc file has been compiled, it creates a file with extension .res. In Borland C++ Builder, you must explicitly compile the resource file, which is easy but you must remember to do it. Microsoft Visual C++ transparently compiles the rc file for you but you must have added it to your project.

After creating the resource file, because the Resource header file holds the identifiers of the resource, remember to include it in the file where you want to use the resources. This is done with a simple:

#include "Resource.h"

To use your own cursor, assign the result of the LoadCursor() function to the hCursor member variable of the WNDCLASS or the WNDCLASSEX class. The first argument of the function should be the instance of the application you are using. For the second argument, use the MAKEINTRESOURCE macro, passing it the identifier of the cursor.

Practical Learning Practical Learning: Using a Cursor

  1. If you are using Borland C++ Builder, click the Resources1.rc tab in the Code Editor
  2. Then, on the main menu, click Project -> Compile Unit. After the resource file has been compiled, click OK
     

    In both compilers, change the Main.cpp file as follows:

    //---------------------------------------------------------------------------
    #include <windows.h>
    #include "resource.h"
    //---------------------------------------------------------------------------
    HWND hWnd;
    const char ClsName[] = "SimpleWindow";
    const char WindowCaption[] = "A Simple Window";
    LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
    //---------------------------------------------------------------------------
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
    {
        MSG         Msg;
        WNDCLASSEX  WndClsEx;
    
        WndClsEx.cbSize        = sizeof(WNDCLASSEX);
        WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
        WndClsEx.lpfnWndProc   = WndProc;
        WndClsEx.cbClsExtra    = NULL;
        WndClsEx.cbWndExtra    = NULL;
        WndClsEx.hInstance     = hInstance;
        WndClsEx.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClsEx.hCursor       = LoadCursor(hInstance, 
                                            MAKEINTRESOURCE(IDC_TARGET));
        WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        
        . . . No Change
    
        return Msg.wParam;
    }
    //---------------------------------------------------------------------------
    LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    {
        . . . No Change
    }
    //---------------------------------------------------------------------------
  3. To execute your program, in Borland C++ Builder, on the main menu, click Project -> Build Resources1. When it is ready, press F9
    In Microsoft Visual C++, press Ctrl + F5 and Enter
     
    Resources Fundamentals
  4. Close the window and return to your programming environment
 

Icons

 

Introduction

An Icon is a small picture that displays in various places to represent an application. For example, an icon displays on the top-left section of the title and is defined by the application. In this case it also holds the system menu. An icon is also used in Windows Explorer and My Computer to represent an application. Icons are also used by other controls (tree views, list views, combo boxes, etc).

The Win32 library ships with only a few icons. Microsoft Windows, on the other hand, ships with various icons for its internal use. The icon we have used so far is a standard icon provided in case you don't have one on your own. This means that you are free to create a custom icon for your application.

Icon Creation

To provide your own icon for your application, you should create one or two icons (you can even create more) for your application. Both icons have the same name and, in fact, are stored as one file. Internally, the operating system will choose which one to display and when, depending on the scenario.

An icon is created following the same steps as we described for a cursor, with a few differences. While a cursor is mostly limited to two colors, an icon can use up to 16 colors.

 

Practical Learning Practical Learning: Creating an Icon

  1. If you are using C++ Builder, on the main menu of Image Editor, click File -> Icon File (.ico). In the Icon Properties dialog box, make sure 32x32 is selected and click OK
     
    Icon Properties
     
    If you are using Visual C++, display the Add Resource dialog box and double-click Icon
  2. Design the icon as follows:
     
    Icon Design
  3. To associate a 16x16 icon:
    If you are using Image Editor, on its toolbar, click New, make sure the 16 x 16 radio button is selected
     


    and click OK
    If you are using Visual C++, on the toolbar of the image, click the button with a lens. In the New Icon Image, click Small (16x16) 



    and click OK
  4. Design the icon as follows
     
    Icon Design2
  5. If you are using Image Editor, save the icon in the folder of the current project as resfund
    If you are using Visual C++, change the ID of the icon to IDI_RESFUND and its file name to resfund.ico
  6. To add the new icon to the resource, if you are using C++ Builder, add its identifier in the Resource.h header file with a 1001 constant:
     
    #define IDC_TARGET  1000
    #define IDI_RESFUND 1001

    Still in C++ Builder, add a resource for the icon in the rc file:
     

    #include "Resource.h"
    
    IDC_TARGET  CURSOR  "Target.cur"
    IDI_RESFUND ICON    "resfund.ico"


    To use the new icon in the application, change the Exercise.cpp source file as follows:
     

    //---------------------------------------------------------------------------
    #include <windows.h>
    #pragma hdrstop
    
    #include "Resource.h"
    //---------------------------------------------------------------------------
    
    #pragma argsused
    //---------------------------------------------------------------------------
    const char *ClsName = "FundApp";
    const char *WndName = "Resources Fundamentals";
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg,
    			                  WPARAM wParam, LPARAM lParam);
    //---------------------------------------------------------------------------
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine, int nCmdShow)
    {
    	MSG        Msg;
    	HWND       hWnd;
    	WNDCLASSEX WndClsEx;
    
    	// Create the application window
    	WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    	WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    	WndClsEx.lpfnWndProc   = WndProcedure;
    	WndClsEx.cbClsExtra    = 0;
    	WndClsEx.cbWndExtra    = 0;
    	WndClsEx.hIcon         = LoadIcon(hInstance,
                                              MAKEINTRESOURCE(IDI_RESFUND));
    	WndClsEx.hCursor       = LoadCursor(hInstance,
                                            MAKEINTRESOURCE(IDC_TARGET));
    	WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	WndClsEx.lpszMenuName  = NULL;
    	WndClsEx.lpszClassName = ClsName;
    	WndClsEx.hInstance     = hInstance;
    	WndClsEx.hIconSm       = LoadIcon(hInstance,
    					  MAKEINTRESOURCE(IDI_RESFUND));
    
    	// Register the application
    	RegisterClassEx(&WndClsEx);
    
    	. . . No Change
    
    	return Msg.wParam;
    }
    //---------------------------------------------------------------------------
    LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg,
    			   WPARAM wParam, LPARAM lParam)
    {
        . . . No Change
    }
    //---------------------------------------------------------------------------
  7. In C++ Builder, compile the .rc file again. To execute your program, in Borland C++ Builder, on the main menu, click Project -> Build Resources1. When it is ready, press F9
    In Visual C++, simply press Ctrl + F5 to execute the application
     
    Resource Fundamentals
  8. Return to your programming environment
 

Previous Copyright © 2003-2005 FunctionX, Inc. Next